﻿using AutojsController.Config;
using AutojsController.Helpers;
using AutojsController.ViewModels;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;


namespace AutojsController.Services
{
    public class MobileChangeEventArgs : System.EventArgs
    {
        public Mobile Mobile { get; }
        public MobileChangeEventType ChangeType { get; }
        public MobileChangeEventArgs(Mobile mobile, MobileChangeEventType changeType)
        {
            Mobile = mobile;
            ChangeType = changeType;
        }
    }

    public class MobilesService : IDBService
    {
        public ObservableCollection<MobileItemViewModel> MobileItems { get; } = new ();
        //还是需要使用ObservableCollection<MobileItemViewModel>, 因为MobileItemViewModel中有mobile实时操作属性，这些状态要在不同面板里都相同
        //public Dictionary<int, Mobile> CachedMobileDict = new();
        //public delegate void MobileChangedHandler(MobileChangeEventArgs e);
        //public event MobileChangedHandler? MobileChangedEvent;

        public MobilesService(IDbContextFactory<DBContext> dbContextFactory) : base(dbContextFactory)
        {
            using var db = dbFactory.CreateDbContext();
            MobileItems = new ObservableCollection<MobileItemViewModel>(db.mobiles.Select(m => new MobileItemViewModel(m)));
        }

        public async Task<List<Mobile>> GetAllMobilesAsync()
        {
            using var db = await dbFactory.CreateDbContextAsync();
            return await db.mobiles.ToListAsync();
        }

        public async Task<Mobile?> GetMobileByIdAsync(int id)
        {
            using var db = await dbFactory.CreateDbContextAsync();
            return await db.mobiles.FindAsync(id);
        }

        public async Task<List<Mobile>> GetMobilesByGroupIdAsync(int groupId)
        {
            using var db = await dbFactory.CreateDbContextAsync();
            return await db.mobiles.Where(m => m.GroupId == groupId).ToListAsync();
        }

        public async Task<Mobile> AddMobileAsync(Mobile mobile)
        {
            if (IsMaximunDeviceCountReached())
                throw new MobileCountLimitExceededException($"已达到最大设备数{Consts.MAX_MOBILE_COUNT}，无法添加更多设备");
            using var db = await dbFactory.CreateDbContextAsync();
            var exist = await db.mobiles.Where(m => m.Address == mobile.Address).CountAsync() > 0;
            if (exist) throw new DuplicateMobileException();
            db.mobiles.Add(mobile);
            await db.SaveChangesAsync();
            MobileItems.Add(new MobileItemViewModel(mobile));
            //CachedMobileDict[mobile.Id] = mobile;
            //MobileChangedEvent?.Invoke(new MobileChangeEventArgs(mobile, MobileChangeEventType.Added));
            return mobile;
        }

        public async Task<Mobile> AddMobileAsync(string ip, string? deviceType, int? GroupId)
        {
            var mobile = new Mobile
            {
                Address = ip,
                DeviceType = deviceType,
                GroupId = GroupId
            };
            await AddMobileAsync(mobile);
            return mobile;
        }

        public async void UpdateMobileAsync(Mobile mobile)
        {
            using var db = await dbFactory.CreateDbContextAsync();
            db.mobiles.Update(mobile);
            await db.SaveChangesAsync();
            var mobileVM = MobileItems.FirstOrDefault(m => m.Mobile.Id == mobile.Id);
            if (mobileVM != null)
                mobileVM.Mobile = mobile;
            //CachedMobileDict[mobile.Id] = mobile;
            //MobileChangedEvent?.Invoke(new MobileChangeEventArgs(mobile, MobileChangeEventType.Updated));
        }

        private async Task deleteMobileAsync(int id)
        {
            using var db = await dbFactory.CreateDbContextAsync();
            var mobile = await db.mobiles.FindAsync(id);
            if (mobile != null)
            {
                db.mobiles.Remove(mobile);
                await db.SaveChangesAsync();
            }
            var mobileVM = MobileItems.FirstOrDefault(m => m.Mobile.Id == id);
            if (mobileVM != null)
                MobileItems.Remove(mobileVM);
            //CachedMobileDict.Remove(id);
            //MobileChangedEvent?.Invoke(new MobileChangeEventArgs(mobile!, MobileChangeEventType.Deleted));
        }

        /// <summary>
        /// 删除前判断MobileItemViewModel的状态，只允许删除连接或者已连接的设备
        /// </summary>
        public async Task SafeDeleteMobileAsync(int id)
        {
            var mobileVM = MobileItems.FirstOrDefault(m =>m.Mobile.Id == id);
            if (mobileVM != null)
            {
                if (mobileVM.Status != MobileStatus.Disconnected && mobileVM.Status != MobileStatus.Connected)
                    throw new DeleteMobileForbiddenException("只允许删除未连接或者已连接(未运行)状态的设备");
                if (mobileVM.connection != null)
                    mobileVM.connection.Disconnect();
            }

            using var db = await dbFactory.CreateDbContextAsync();
            await db.mobiles.Where(m=>m.Id == id).ExecuteDeleteAsync();
            if (mobileVM != null) MobileItems.Remove(mobileVM);
        }

        public async Task<Mobile?> AddMobileToGroup(int mobileId, int GroupId)
        {
            using var db = await dbFactory.CreateDbContextAsync();
            var mobile = await db.mobiles.FindAsync(mobileId);
            if (mobile != null)
            {
                mobile.GroupId = GroupId;
                await db.SaveChangesAsync();
                return mobile;
            }
            return null;
        }

        public bool IsMaximunDeviceCountReached()
        {
            return MobileItems.Count >= Consts.MAX_MOBILE_COUNT;
        }

        public async Task RemoveMobileFromGroupAsync(int mobileId, int groupId)
        {
            using var db = await dbFactory.CreateDbContextAsync();
            var mobile = await db.mobiles.FindAsync(mobileId);
            if (mobile?.GroupId == groupId)
            {
                mobile.Group = null;
                mobile.GroupId = null;
                await db.SaveChangesAsync();
                var mi = MobileItems.Where(m => m.Mobile.Id == mobile.Id).FirstOrDefault();
                if (mi != null) mi.Mobile = mobile;
            }
        }

        public async Task<List<Mobile>> GetRandomAvalibleMobilesAsync(int count)
        {
            using var db = await dbFactory.CreateDbContextAsync();
            return await db.mobiles.Where(m => m.Group == null).OrderBy(m => EF.Functions.Random()).Take(count).ToListAsync();
        }
    }
}
